/*
 * Patient.java
 *
 * @version 1.0
 * CS 2340 Team 10: Cyberdyne Systems
 */

package edu.gatech.oad.cyberdoc.domain;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import edu.gatech.oad.cyberdoc.domain.action.ActionHandleException;
import edu.gatech.oad.cyberdoc.domain.action.ActionHandler;

/**
 * Represents a patient in the system and contains static methods to manage all
 * patients.
 * 
 * @author John Girata
 * @version 1.0, March 17, 2011
 */
public class Patient extends User {
	/**
	 * The logger for this class.
	 */
	private static final Logger LOG;

	/**
	 * The handlers for the actions a Patient can perform.
	 */
	private static Map<String, ActionHandler> Handlers;

	/**
	 * The names of the legal fields for a Patient instance.
	 */
	private static final List<String> KEYS;

	/**
	 * The information stored by a Patient.
	 */
	private final Map<String, Object> infoHash;

	/**
	 * This patient's history of weights.
	 */
	private int[] weights;

	static {
		LOG = Logger.getLogger("edu.gatech.oad.cyberdoc.domain.Patient");
		KEYS = new ArrayList<String>();
		Handlers = new HashMap<String, ActionHandler>();

		KEYS.add("name");
		KEYS.add("address");
		KEYS.add("phone");
		KEYS.add("email");
		KEYS.add("gender");
		KEYS.add("age");
		KEYS.add("pharmacy");
		KEYS.add("carrier");
		KEYS.add("allergies");

	}

	/**
	 * Creates a new Patient with the given username and password.
	 * 
	 * @param username
	 *            The Patient's username
	 * @param password
	 *            The Patient's password
	 */
	public Patient(String username, String password) {
		super(username, password);
		infoHash = new HashMap<String, Object>();
	}

	/**
	 * Creates an instance of this class from a JSONObject, as required by
	 * DatabaseSerializable.
	 * 
	 * @param object
	 *            The JSONObject to deserialize
	 */
	public Patient(JSONObject object) {
		super(object);
		infoHash = new HashMap<String, Object>();

		try {
			if (object.has("weights")) {
				JSONArray weights = object.getJSONArray("weights");
				this.weights = new int[weights.length()];
				for (int i = 0; i < weights.length(); i++) {
					this.weights[i] = weights.getInt(i);
				}
			}
		} catch (JSONException e) {
			LOG.log(Level.SEVERE, "Unexpected execption", e);
		}
	}

	/**
	 * Handles the actions that a Patient can perform.
	 * 
	 * @param command
	 *            The command passed from the user
	 * @return The result of handling the command
	 * @throws UnsupportedOperationException
	 *             If the action specified in the command is not recognized
	 * @throws ActionHandleException
	 *             If an ActionHandleException is thrown by the specific
	 *             ActionHandler
	 */
	@Override
	public JSONObject handle(JSONObject command)
			throws UnsupportedOperationException, ActionHandleException {
		JSONObject response = null;

		try {
			final ActionHandler handler = Handlers.get(command
					.getString("action"));

			if (handler != null) {
				response = handler.handle(this, command);
			} else {
				throw new UnsupportedOperationException("Action "
						+ command.getString("action") + " not supported.");
			}
		} catch (JSONException e) {
			LOG.severe("Required field 'action' does not exist in command.");
			throw new ActionHandleException(e);
		}

		return response;
	}

	/**
	 * Registers an ActionHandler with this class.
	 * 
	 * @param action
	 *            The action codes to register to
	 * @param handler
	 *            The handler to respond to the action code
	 */
	public static void addActionHandler(String action, ActionHandler handler) {
		Handlers.put(action, handler);
	}

	/**
	 * Removes an action handler that was previously registered.
	 * 
	 * @param handler
	 *            The ActionHandler to remove
	 */
	public static void removeActionHandler(ActionHandler handler) {
		final Collection<ActionHandler> values = Handlers.values();

		while (values.contains(handler)) {
			values.remove(handler);
		}
	}

	/**
	 * Serializes this Patient instance as a JSONObject
	 * 
	 * @return This instance as a JSONObject
	 * @throws JSONException
	 *             If an exception occurs while converting this instance to a
	 *             JSONObject
	 */
	@Override
	public JSONObject toJSONObject() {
		final JSONObject object = super.toJSONObject();

		for (String key : KEYS) {
			if (infoHash.containsKey(key)) {
				try {
					object.put(key, infoHash.get(key));
				} catch (JSONException e) {
					LOG.log(Level.SEVERE, "Unexpected JSONException", e);
				}
			}
		}

		try {
			if (weights != null) {
				JSONArray array = new JSONArray();
				
				for (int weight : weights) {
					array.put(weight);
				}
				
				object.put("weights", array);
			}
		} catch (JSONException e) {
			LOG.log(Level.SEVERE, "Unexpected JSONException", e);
		}

		return object;
	}

	// public ArrayList<TreatmentRecord> getHistory() {
	// return history;
	// }
}
